<HTML>
<HEAD>
<TITLE>FDJS Dependent menus example</TITLE>

<script src="fdjs.js"></script>

<script language="JavaScript1.2">

//////////////////////////////////////////////////////////////////
//
//   FDJS Linked input Example
//   (c) Kerry Clendinning, 2007
//
//   This is a simple example to demonstrate functional declarative
//   programming in javascript, using the FDJS libary.
//
//   Licensed under the Mozilla Public License 1.1
//   http://www.mozilla.org/MPL/
//
//   This header must remain intact.
//
//   Project homepage http://code.google.com/p/fdjs/
//
//////////////////////////////////////////////////////////////////

  function calculator_example() {

     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     //: the display is output as HTML and shows the result of any of the    :
     //: function keys, or the cumulative numeric entry from the number keys :
     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     calc_display  = new FDJSValue( kscreen, 
                                    "innerHTML",
                                    function() { return FDJSRecent ( calc_num, 
                                                                     calc_clear,
                                                                     calc_plus,
                                                                     calc_minus,
                                                                     calc_mult,
                                                                     calc_divide,
                                                                     calc_recipr,
                                                                     calc_chs,
                                                                     calc_equals ) } )

     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     //: a class for numeric buttons to return their value on each click :
     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     FDJSInherit( numButton )
     function numButton ( element ) {
          FDJSValue.call( this, element, "value", null, "onclick" )
          this.setNotify()
     }

     //:::::::::::::::::::::::::::::::
     //: an instance for each number :
     //:::::::::::::::::::::::::::::::

     numberButtons = [ new numButton( kz ), new numButton( k0 ),
          new numButton( k1 ), new numButton( k2 ), new numButton( k3 ), 
          new numButton( k4 ), new numButton( k5 ), new numButton( k6 ), 
          new numButton( k7 ), new numButton( k8 ), new numButton( k9 ) ]

     dimDecimalPoint = new FDJSValue( kz, "style.visibility", 
         function () { return FDJSIf ( calc_display.getValue().indexOf('.') > -1,
                     "hidden", "visible" ) } )

     //:::::::::::::::::::::::::::::::::::::::::::::
     //: Numeric entry is handled by concatenating :
     //: keypresses from the number keys           :
     //:::::::::::::::::::::::::::::::::::::::::::::

     calc_num    = new FDJSNotifyValue( 
              function () { return FDJSIf( calc_entry_mode.peekValue(), 
                                           calc_display.peekValue(), "" ) + 
                                           FDJSRecent ( numberButtons ) } )
     calc_num.setFormulaName("calc_num")

     //::::::::::::::::::::::::::::::::::::::::::::::::
     //: after any function key, the display is reset :
     //: and ready to accept new numeric input.       :
     //::::::::::::::::::::::::::::::::::::::::::::::::

     calc_reset  = new FDJSNotifyValue ( 
            function () { calc_fcn.getDependency(); 
                          calc_recipr.getDependency();
                          return 0 } )
     calc_reset.setFormulaName("calc_reset")

     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     //: determine the entry mode: reset (0) or numeric (not 0) :
     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     calc_entry_mode  = new FDJSValue ( function () { return FDJSRecent( calc_reset,
                                                                         calc_num ) } )
     calc_entry_mode.setFormulaName("calc_entry_mode")

     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     //: a function key ( +, -, C,... ) doesn't take effect until the other ("y") :
     //: value is entered, so we store a closure (function) to execute later!     :
     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

     calc_fcn   = new FDJSNotifyValue( 
            function () { return ( FDJSRecent( calc_clear,
                                               calc_plus.keypress,
                                               calc_minus.keypress,
                                               calc_mult.keypress,
                                               calc_divide.keypress,
                                               calc_equals
                                   ) ) } )
     calc_fcn.setFormulaName("calc_fcn")

     //::::::::::::::::::::::::::::::::::::::::::::
     //: we also have to stash away the "x" value :
     //::::::::::::::::::::::::::::::::::::::::::::
     
     calc_x_value  = new FDJSValue ( 
            function () { calc_fcn.getDependency(); 
                          return calc_display.peekValue()} )
     calc_x_value.setFormulaName("calc_x_value")

     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     //: evaluate the stashed function, "x" value and "y" value :
     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
     
     eval_fcn = function () {
        var oper = calc_fcn.peekValue()
        var x = parseFloat(calc_x_value.peekValue())
        var y = parseFloat(calc_display.peekValue())
        if ( typeof oper == 'function' ) {
            return oper( x, y )
        } else
            return y
     }

     //:::::::::::::::::::::::::::::::::::::::::::::
     //: helper class to make function keys return :
     //: their closure (function) when pressed     :
     //:::::::::::::::::::::::::::::::::::::::::::::
     
     FDJSInherit( calcKeypress )
     function calcKeypress ( obj, oper ) {
          FDJSValue.call ( this, function () { obj.getDependency(); return (oper) } )
          this.setNotify()
          this.setFormulaName(obj.parent.id + ' keypress')
     }

     //::::::::::::::::::::::::::::::::::::::::::
     //: the function key will also process any :
     //: pending eval_fcn from a prior keypress :
     //::::::::::::::::::::::::::::::::::::::::::
     
     FDJSInherit( calcFunction )
     function calcFunction ( element, oper ) {
          FDJSValue.call( this, element, eval_fcn, null, "onclick" )
          this.keypress = new calcKeypress ( this, oper )
          this.setNotify()
     }

     //::::::::::::::::::::::::::::::::::::::::
     //: modifier keys operate immediately on :
     //: the value currently in the display   :
     //::::::::::::::::::::::::::::::::::::::::
     
     FDJSInherit( calcModifier )
     function calcModifier ( element, oper ) {
          this.fcn = function (x) { return oper(parseFloat(calc_display.peekValue())) }
          FDJSValue.call( this, element, this.fcn, null, "onclick" )
          this.setNotify()
     }

     //::::::::::::::::::::::::::::::::::::::::::::::
     //: instantiate the function and modifier keys :
     //::::::::::::::::::::::::::::::::::::::::::::::

     calc_equals = new calcFunction ( ke, function ( x ) { return ( x ) } )
     calc_plus   = new calcFunction ( kp, function (x,y) { return (x + y) } )
     calc_minus  = new calcFunction ( km, function (x,y) { return (x - y) } )
     calc_mult   = new calcFunction ( kx, function (x,y) { return (x * y) } )
     calc_divide = new calcFunction ( kd, function (x,y) { return (x / y) } )
     calc_recipr = new calcModifier ( kr, function ( x ) { return (1 / x) } )
     calc_clear  = new calcModifier ( kc, function ( x ) { return ( 0 ) } )
     calc_chs    = new calcModifier ( ks, function ( x ) { return (0 - x) } )

     //:::::::::::::::::::::::::::::::::::::::::::::::
     //: be sure to detect the dependencies, to make :
     //: the declarative relationships live          :
     //:::::::::::::::::::::::::::::::::::::::::::::::

     FDJSValue.prototype.dependTracker.detect( )

  // <tr> <td id="kmscreen" colspan="6">  M: </td>  </tr>
  // <td> <input type=submit id="kmc" value="MC"/></td> 
  // <td> <input type=submit id="kmr" value="MR"/></td>
  // <td> <input type=submit id="kms" value="MS"/></td> 
  // <td> <input type=submit id="kmp" value="M+"/></td> 
  }
</script>
  
</HEAD>
<BODY onload="calculator_example(); return false">
  <B>Calculator example</B><BR>

    <table border="1">
      <tr> <td align="right" colspan="5"><pre id="kscreen"/> </td> </tr>
      <tr>
           <td> <input type=submit id="k7" value="7"/></td> 
           <td> <input type=submit id="k8" value="8"/></td> 
           <td> <input type=submit id="k9" value="9"/></td> 
           <td> <input type=submit id="kd" value="/"/></td> 
           <td> <input type=submit id="kc" value="C"/></td> 
      <tr>
           <td> <input type=submit id="k4" value="4"/></td> 
           <td> <input type=submit id="k5" value="5"/></td> 
           <td> <input type=submit id="k6" value="6"/></td> 
           <td> <input type=submit id="kx" value="*"/></td> 
           <td> <input type=submit id="ks" value="+/-"/></td> </td> </tr>
      <tr> 
           <td> <input type=submit id="k1" value="1"/></td> 
           <td> <input type=submit id="k2" value="2"/></td> 
           <td> <input type=submit id="k3" value="3"/></td> 
           <td> <input type=submit id="km" value="-"/></td> 
           <td> <input type=submit id="kr" value="1/x"/></td> 
      <tr>
           <td> <input type=submit id="k0" value="0"/></td> 
           <td> <input type=submit id="kz" value="." style="visibility:visible"/></td> 
           <td> <input type=submit id="kp" value="+"/></td> 
           <td> <input type=submit id="ke" value="="/></td>  </tr>
  </table>
  <P>
  <INPUT TYPE=SUBMIT ONCLICK="FDJSValue.prototype.setLogger( 'EVENTLOG' )" VALUE="Log Events"/>
  <PRE ID="EVENTLOG"></PRE>

</BODY>
</HTML>
